/*********************************************************************************
 *     File Name           :     main.c
 *     Created By          :     xiaogebin
 *     Creation Date       :     [2024-12-23 11:27]
 *     Last Modified       :     [2025-01-06 11:15]
 *     Description         :     歌词显示
 **********************************************************************************/

#include "lyric.h"
#include <errno.h>
#include <fcntl.h>
#include <pcre.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

#define MAX_MATCHES 100
char** buf = NULL;
int line_num = 0;

typedef struct lyric_status {
    unsigned int current_time;
    int line_index;
} lyric_status, *p_lyric_status;

enum MOC_SONG_PLAY_STATUS {
    SONG_STOP,
    SONG_PLAYING
};
typedef struct lyric_moc_status {
    long current_time_sec;
    long total_sec;
    char song_name[128];
    char song_path[1024];
    char song_title[1024];
    enum MOC_SONG_PLAY_STATUS msps;
} lyric_moc_status, *p_lyric_moc_status;

float get_lyric_during_time(float start, const char* lyric_line, char* save_lyric);
char** split_time_lyric(const char* line, const char* pattern, int* group_num);
void delay_ms(int milliseconds);
long lyric_to_delay_time(const char* lyric_line, char* save_lyric);
int readlines();

p_lyric_status get_lyric_status(long current_time, long total_time);
char** get_moc_song_lyric_basedir(p_lyric_moc_status);

int get_moc_song_status(p_lyric_moc_status plms);
char* get_file_prefix(const char*);

lyric_moc_status lms;

char current_song_name[128] = {0};

int loop()
{/*{{{*/

    int n = 0;
    long start_time = 0;
    long current_time = 0;
    int flg = 0; // 还没碰到过
    int pre = n;
    int flg1 = 0;
    char save_lyric[1024] = { '\0' };
    /* printf("total_sec: %ld", lms.total_sec); */
    /* printf("current_time_sec: %ld", lms.current_time_sec); */
    /* printf("line_num: %d\n", line_num); */
    /* system("clear"); */

    p_lyric_status pls = get_lyric_status(lms.current_time_sec, lms.total_sec); //获取歌词信息
    n = pls->line_index;
    current_time = pls->current_time * 1000; // 秒转为毫秒
    /* printf("n: %d\n", n); */
    /* printf("current_time: %ld\n", current_time); */
    while (1) {

        get_moc_song_status(&lms);
        if (lms.msps == SONG_STOP) {
            /* delay_ms(1000); */
            /* printf("lms.msps: %s\n", "SONG_STOP"); */
            continue;
        }
        if (n == line_num) {
            n = pre = 0;
            /* start_time = 0.0f; */
            current_time = 0;
            break;
        }
        memset(save_lyric, 0, sizeof(save_lyric) / sizeof(char));
        start_time = lyric_to_delay_time(buf[n], save_lyric);
        if (start_time < current_time && flg == 0) { // 时间遇到，切之前没碰到的情况就打印
            /* system("clear"); */
            printf("                         \033[32m%s\033[0m\n", save_lyric);
            n++;
            flg = 1; // 设置没碰到为碰到
        }

        /* if (start_time < current_time && flg == 1) { // 时间遇到，但之前碰到的情况就不打印 */
        /*     #<{(| system("clear"); |)}># */
        /* } */

        if (pre != n) { // 表示有所更新
            flg = 0;    // 重置flg为未碰过
            pre = n;    // 重置tmp为n
        }
        lyric_moc_status lms;
        get_moc_song_status(&lms);
        if (strcmp(lms.song_path, current_song_name) != 0) {
            memset(current_song_name, 0, 128);
            strcpy(current_song_name, lms.song_path);
            /* printf("发现切歌了\n"); */
            return 1;

        }
        current_time += 1000;
        delay_ms(1000);
    }
    system("clear");
    return 0;
}/*}}}*/

int main(int argc, char* argv[])
{ /*{{{*/

    int ret;
    while (1) {
        ret = readlines();
        /* printf("current_song_name: %s\n", current_song_name); */
        if (ret != 0) {
            /* system("clear"); */
            printf("\033[41m监听中!!\033[0m\n");
            sleep(2);
        } else {
            loop();
        }

    }
    return 0;
} /*}}}*/

/* int main(int argc, char* argv[]) */ /*{{{*/
/* {#<{(|{{{|)}># */
/*     int n = 0; */
/*     long start_time = 0; */
/*     readlines(); */
/*     long current_time = 0; */
/*     int flg = 0; // 还没碰到过 */
/*     int pre = n; */
/*     int flg1 = 0; */
/*     char save_lyric[1024] = { '\0' }; */
/*     int is_read_geci = 0; */
/*     while (1) { */
/*         if (n == line_num) { */
/*             n = pre = 0; */
/*             #<{(| start_time = 0.0f; |)}># */
/*             current_time = 0; */
/*             break; */
/*         } */
/*         if (is_read_geci != 1) { */
/*             memset(save_lyric, 0, sizeof(save_lyric)/sizeof(char)); */
/*             start_time = lyric_to_delay_time(buf[n], save_lyric); */
/*             is_read_geci = 1; */
/*         } */
/*         if (start_time < current_time) { // 时间遇到，切之前没碰到的情况就打印 */
/*             system("clear"); */
/*             printf("\n\n                         \033[1;32m%s\033[0m\n", save_lyric); */
/*             n++; */
/*             is_read_geci = 0; */
/*         } */
/*  */
/*         current_time+=10; */
/*         delay_ms(10); */
/*     } */
/*     return 0; */
/* }#<{(|}}}|)}># */ /*}}}*/

int readlines()
{ /*{{{*/
    char buffer[1024];
    int ret = get_moc_song_status(&lms);
    if (ret != 0) {
        printf("%s\n", "get_moc_song_status failed\n");
    }

    /* printf("read file\n"); */
    /* printf("song's name : %s\n", lms.song_path); */
    if (ret != 0) {
        return 1;
    }
    char* song_lyric_ab_filename = get_moc_song_lyric_basedir(&lms)[2];
    /* printf("song_lyric_ab_filename: %s\n", song_lyric_ab_filename); */
    // 查看有没有该歌词文件, 没有的话就尝试下载
    /* printf("song_lyric_ab_filename: %s\n", song_lyric_ab_filename); */
    struct stat s;
    if (stat(song_lyric_ab_filename, &s)!=0){
        // 文件不存在的情况, 尝试下载
        /* printf("lms:song_name: %s\n", lms.song_name); */
        int ret = download_lrc(lms.song_name, song_lyric_ab_filename);
        /* printf("ret: %d\n", ret); */
        if ( ret == 0) {
            // 下载成功
            printf("下载%s的歌词成功\n", lms.song_name);
        } else {
            printf("下载%s的歌词失败\n", lms.song_name);
            return 2;
        }
    }
    FILE* pf = fopen(song_lyric_ab_filename, "r");
    if (pf == NULL) {
        return 1;
    }

    line_num = 0;
    while (1) {
        char* p = fgets(buffer, 1024, pf);
        if (p == NULL) {
            break;
        }
        /* printf("%s\n", p); */
        if (p != NULL) {
            if (line_num == 0) {
                buf = (char**)malloc(sizeof(char*) * 1);
            } else {
                buf = (char**)realloc(buf, sizeof(char*) * (line_num + 1));
                if (buf == NULL) {
                    printf("error to realloc!!");
                    return 1;
                }
            }
            char* line_str = (char*)malloc(sizeof(char) * (strlen(p) + 1));
            memcpy(line_str, p, strlen(p) + 1);
            line_str[strlen(p) - 1] = '\0';
            /* printf("%s\n", line_str); */
            buf[line_num] = line_str;
            line_num++;
        }
    }
    fclose(pf);
    memset(current_song_name, 0, 128);
    strcpy(current_song_name, lms.song_path);
    return 0;
} /*}}}*/

char** split_time_lyric(const char* line, const char* pattern, int* group_num)
{ /*{{{*/
    /* const char* line = "Hello, (123) 456-7890"; */
    /* const char* pattern = "(\\(\\d{3}\\)) \\d{3}-\\d{4}"; */
    pcre* re;
    pcre_extra* extra;
    const char* error;
    int erroffset;
    int ovector[30];
    char** groups = NULL;

    if ((re = pcre_compile(pattern, 0, &error, &erroffset, NULL)) == NULL) {
        printf("pcre compilation failed at offset %d: %s\n", erroffset, error);
        return NULL;
    }

    if ((extra = pcre_study(re, 0, &error)) == NULL) {
        if (error)
            printf("pcre study failed: %s\n", error);
        pcre_free(re);
        return NULL;
    }

    int rc = pcre_exec(re, extra, line, strlen(line), 0, 0, ovector, 30);
    if (rc < 0) {
        if (rc == PCRE_ERROR_NOMATCH) {
            printf("Sorry, no match..\n");
        } else {
            printf("Mathching error %d\n", rc);
        }
    } else {
        /* printf("Match OK\n"); */
        groups = (char**)malloc(sizeof(char*) * rc);
        for (int i = 0; i < rc; ++i) {
            int start = ovector[2 * i];
            int end = ovector[2 * i + 1];
            /* printf("Group %d: %.*s\n", i, end - start, line + start); */
            char* group_str_buf = (char*)malloc(sizeof(char) * (end - start) + 1);
            sprintf(group_str_buf, "%.*s", end - start, line + start);
            groups[i] = group_str_buf;
        }
        *group_num = rc;
    }

    // clean
    pcre_free(re);
    pcre_free(extra);
    return groups;
} /*}}}*/

long lyric_to_delay_time(const char* lyric_line, char* save_lyric)
{ /*{{{*/
    /*
     * 从歌词中提取时间段，并转换为毫秒
     */
    int groups_num = 0;
    char** groups = split_time_lyric(lyric_line, "(\\[\\d{2}:\\d{2}\\.\\d{2}\\])(.*)", &groups_num);
    /* printf("groups_num:%d\n", groups_num); */
    if (groups == NULL) {
        printf("NO MATCH \n");
        return -1;
    }

    /* printf("%s    %s\n", groups[1], groups[2]); */
    int minutes = 0;
    float seconds = 0.0;
    sscanf(groups[1], "[%d:%f]", &minutes, &seconds);
    // 保存歌词
    /* printf("%s\n", groups[2]); */
    memcpy(save_lyric, groups[2], strlen(groups[2]));
    // 是否内存
    for (int i = 0; i < groups_num; i++) {
        if (groups[i] != NULL) {
            /* printf("释放groups[%d]\n", i); */
            free(groups[i]);
            groups[i] = NULL;
        }
    }
    /* printf("释放groups\n"); */
    if (groups != NULL) {
        free(groups);
    }
    groups = NULL;
    /* printf("%d\n", minutes); */
    /* printf("%0.2f\n", seconds); */
    double during;
    during = (float)minutes * 60 + seconds;
    return during * 1000;
} /*}}}*/

float get_lyric_during_time(float start, const char* lyric_line, char* save_lyric)
{ /*{{{*/
    //"[01:42.03]夜夜想你念你 盼你回到我身边"
    int groups_num = 0;
    char** groups = split_time_lyric(lyric_line, "(\\[\\d{2}:\\d{2}\\.\\d{2}\\])(.*)", &groups_num);
    if (groups == NULL) {
        printf("NO MATCH \n");
        return -1;
    }

    /* printf("%s    %s\n", groups[1], groups[2]); */
    int minutes = 0;
    float seconds = 0.0;
    sscanf(groups[1], "[%d:%f]", &minutes, &seconds);
    // 保存歌词
    printf("%s\n", groups[2]);
    memcpy(save_lyric, groups[2], strlen(groups[2]));
    /* printf("%d\n", minutes); */
    /* printf("%0.2f\n", seconds); */
    float during = 0.0f;
    during = (float)minutes * 60 + seconds;
    /* printf("%0.2f", during); */
    return during - start;
} /*}}}*/

void delay_ms(int milliseconds)
{ /*{{{*/
    struct timespec ts = {
        .tv_sec = milliseconds / 1000,
        .tv_nsec = (milliseconds % 1000) * 1000000
    };

    while ((nanosleep(&ts, &ts) == -1) && (errno == EINTR))
        ;
} /*}}}*/

/*
 * 获取当前时间的歌词行数
 * current_time: 当前时间
 * total_time: 全部时间
 */
p_lyric_status get_lyric_status(long current_time, long total_time)
{/*{{{*/
    int n = 0;
    long start_time;
    char save_lyric[1024] = { '\0' };
    static lyric_status status;
    /* printf("line_num: %d\n", line_num); */
    if (current_time > total_time) {
        return NULL;
    }
    while (1) {
        if (n > line_num - 1) {
            break;
        }
        memset(save_lyric, 0, sizeof(save_lyric) / sizeof(char));
        start_time = lyric_to_delay_time(buf[n], save_lyric) / 1000;
        if (start_time > current_time) { // 时间遇到，切之前没碰到的情况就打印
            /* system("clear"); */
            status.current_time = current_time;
            status.line_index = n - 1;
            return &status; // 输出结果
        } else if (start_time == current_time) {
            status.current_time = current_time;
            status.line_index = n;
            return &status; // 输出结果
        }
        n++;

        /* if (start_time < tmp_time && flg == 1) { // 时间遇到，但之前碰到的情况就不打印 */
        /*     #<{(| system("clear"); |)}># */
        /* } */
    }

    /* current_time 大于最后一个歌词时间的话 */
    status.current_time = current_time;
    status.line_index = n - 1;

    return &status;
}/*}}}*/

int get_moc_song_status(p_lyric_moc_status plms)
{/*{{{*/
    FILE* fp;
    char line[1035];
    long total_sec;
    long current_sec;
    int flg = 0;

    fp = popen("sudo mocp -i", "r");
    if (fp == NULL) {
        printf("run popen failed\n");
        return 1;
    }
    while (fgets(line, 1035, fp) != NULL) {
        /* printf("%s\n", line); */
        if (sscanf(line, "TotalSec: %ld", &total_sec) > 0) {
            /* printf("TotalSec: %ld", total_sec); */
            plms->total_sec = total_sec;
            flg++;
        }

        if (sscanf(line, "CurrentSec: %ld", &current_sec) > 0) {
            /* printf("CurrentSec: %ld", current_sec); */
            plms->current_time_sec = current_sec;
            flg++;
        }

        if (sscanf(line, "Title: %[^\r\n]", plms->song_name) > 0) {
            flg++;
        }

        if (sscanf(line, "File: %s", plms->song_path) > 0) {
            flg++;
        }

        if (sscanf(line, "SongTitle: %s", plms->song_title) > 0) {
            flg++;
        }

        char msps[20] = {0};
        if (sscanf(line, "State: %s", msps) > 0) {
            if (strcmp(msps, "PLAY") == 0) {
                plms->msps = SONG_PLAYING;
            } else {
                plms->msps = SONG_STOP;
            }
            flg++;
        }

    }

    int status = pclose(fp);
    if (status == -1) {
        printf("close failed\n");
        return 1;
    } else {
        /* printf("command exited with status %d\n", status); */
    }

    if (flg == 6) {
        /* 成功获取信息*/
        return 0;
    } else {
        printf("没有截取到四个信息!!");
        return 1;
    }
    return 1;
}/*}}}*/

char** get_moc_song_lyric_basedir(p_lyric_moc_status plmos)
{/*{{{*/
    const char* filepath = plmos->song_path;
    char basedir[1024] = { 0 };
    char tmpname[128] = { 0 };
    char song_lyric_filename[1024] = { 0 };
    char song_lyric_ab_filename[1024] = { 0 };
    int n = 0;
    for (int i = 0; i < strlen(filepath); i++) {
        if (filepath[i] == '/') {
            n++;
        }
    }
    int max_cout = n;
    /* printf("max_cout: %d\n", max_cout); */

    int j;
    n = 0;
    for (j = 0; j < strlen(filepath); j++) {
        if (filepath[j] == '/') {
            n++;
        }
        if (n == max_cout) {
            break;
        }
    }
    j++;
    /* printf("j: %d\n", j); */

    strncpy(basedir, filepath, j);
    strcpy(tmpname, filepath + j);
    /* printf("%s\n", basedir); */
    strcat(song_lyric_filename, get_file_prefix(tmpname));
    strcat(song_lyric_filename, ".lrc");
    /* printf("song_lyric_filename: %s\n", song_lyric_filename); */
    char** tmp = (char**)malloc(sizeof(char*) * 3);
    tmp[0] = basedir;
    tmp[1] = song_lyric_filename;
    strcpy(song_lyric_ab_filename, basedir);
    strcpy(song_lyric_ab_filename + strlen(song_lyric_ab_filename), song_lyric_filename);
    tmp[2] = song_lyric_ab_filename;
    return tmp;
}/*}}}*/

char* get_file_prefix(const char* filename)
{/*{{{*/
    int index = 0;
    static char buf[1024] = { 0 };
    memset(buf, 0, 1024);
    for (int i = 0; i < strlen(filename); i++) {
        if (filename[i] == '.') {
            index = i;
        }
    }
    strncpy(buf, filename, index);
    return buf;
}/*}}}*/
